//-------------------------------------------------------------------
//	Copyright (c) 2010-2012 Zhirnov Andrey
//	This file is part of the "UXGEN" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#include "CRTPassManager.h"
#include "../../AllSystems.h"

namespace Engine
{
namespace RenderUtils
{
	
//----------------------------- Console ---------------------------//

	inline bool IsCommandName(char c)
	{
		return ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' || ( c >= '0' && c <= '9' );
	}

	inline bool IsSpaces(char c)
	{
		return ( c == ' ' || c == 9 );
	}

	bool GetConsoleCommand(const string &sCom, string &sName, string &sParams)
	{
		bool	b_name	= true;
		bool	b_param = false;
		bool	b_str	= false;
		usize	i		= 0;

		for (; i < sCom.Length(); ++i)
		{
			if ( !IsCommandName( sCom[i] ) )
			{
				sName.Copy( sCom.cstr(), i );
				b_name = false;
				break;
			}
		}

		if ( b_name )
			return false;

		for (; i < sCom.Length(); ++i)
		{
			if ( !IsSpaces( sCom[i] ) )
			{
				if ( sCom[i] == '=' ) {
					b_param = true;
					++i;
				}
				break;
			}
		}

		if ( !b_param )
			return false;

		sParams.Reserve( sCom.Length() - i );

		for (; i < sCom.Length(); ++i)
		{
			const char c = sCom[i];

			b_str = c == '\'' ? !b_str : b_str;

			if ( b_str || !IsSpaces( c ) )
				sParams << c;
		}

		return true;
	}
	



//-------------------------- Built-in Pass ------------------------//

	inline bool IsSpaces2(char c)
	{
		return ( c == ' ' || c == 9 || c == '\'' || c == ',' );
	}

	inline bool IsFuncName(char c)
	{
		return ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' || ( c >= '0' && c <= '9' );
	}

	inline bool IsIdent(char c)
	{
		return ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' );
	}

	inline bool IsValue(char c)
	{
		return ( c >= '0' && c <= '9' ) || c == '-' || c == '+';
	}

	inline bool IsString(char c)
	{
		return c == '\'';
	}

	inline bool IsFloat(const char *pStr)
	{
		while ( *pStr != '\0' )
		{
			if ( *pStr == '.' )
				return true;

			++pStr;
		}
		return false;
	}


	bool GetBuiltinFunc(const string &sFunc, string &sName, string_array_t &aParams)
	{
		static const uint	s_uOffset = 8;	// == strlen("builtin_")-1;

		usize	i		= s_uOffset;
		bool	b_name	= false;
		bool	b_str	= false;


		for (; i < sFunc.Length(); ++i)
		{
			const char	c = sFunc[i];

			if ( !IsFuncName( c ) )
			{
				sName.Copy( sFunc.cstr() + s_uOffset, i - s_uOffset );
				b_name = true;
				break;
			}
		}

		if ( !b_name )
			return false;


		for (; i < sFunc.Length(); ++i)
		{
			if ( !IsSpaces( sFunc[i] ) )
			{
				if ( sFunc[i] == '(' ) {
					b_name = false;
					++i;
				}
				break;
			}
		}
		
		if ( b_name )
			return false;

		aParams.PushBack( string() );

		for (; i < sFunc.Length(); ++i)
		{
			const char c = sFunc[i];
			
			b_str = c == '\'' ? !b_str : b_str;

			if ( !b_str )
				if ( c == ',' )
					aParams.PushBack( string() );
				else
				if ( c == ')' )
					break;

			if ( b_str || !IsSpaces2( c ) )
				aParams.Back() << c;
		}

		return true;
	}



//-------------------------- CRTPassManager -----------------------//
/*
=================================================
	
=================================================
*/
	CRTPassManager::CRTPassManager()
	{
		RegisterBuiltinPass( "use_user_postprocess", &_s_CreateUseUserPostProcessPass );
		RegisterBuiltinPass( "draw_render_queue_oc", &_s_CreateDrawRenderQueueOCPass );
		RegisterBuiltinPass( "draw_render_queue", &_s_CreateDrawRenderQueuePass );
		RegisterBuiltinPass( "draw_fs_quad", &_s_CreateDrawFullscreenQuadPass );
		RegisterBuiltinPass( "profiler_begin", &_s_CreateProfilerBeginPass );
		RegisterBuiltinPass( "profiler_end", &_s_CreateProfilerEndPass );
		RegisterBuiltinPass( "clear_buffer", &_s_CreateClearBufferPass );
		RegisterBuiltinPass( "setup_shadow", &_s_CreateSetupShadowPass );
		RegisterBuiltinPass( "setup_light", &_s_CreateSetupLightPass );
		RegisterBuiltinPass( "draw_lights", &_s_CreateDrawLightsPass );
		RegisterBuiltinPass( "set_camera", &_s_CreateSetCameraPass );
	}
	
/*
=================================================
	
=================================================
*/
	CRTPassManager::~CRTPassManager()
	{
	}
	
/*
=================================================
	
=================================================
*/
	void CRTPassManager::Release()
	{
		WARNING( "" );
	}

/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_ProcessConsole(const string_array_t &aConsole, TTechParams &sTech)
	{
		string	s_com_name,
				s_params;

		for (usize i = 0; i < aConsole.Count(); ++i)
		{
			CHECK_RETURN( GetConsoleCommand( aConsole[i], s_com_name, s_params ) );

			if ( s_com_name == "profiling" )
			{
				sTech.bProfiling = s_params == "true";
			}
			else
				return false;
		}
		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_CreatePasses(rt_pass_array_t &aPasses, TTechParams &sTech)
	{
		// cache pass names
		for (usize i = 0; i < sTech.sInit.aBindTexPasses.Count(); ++i)
			sTech.aPassCache.PushBack( TPassName( sTech.sInit.aBindTexPasses[i].sName, i, IRTPass::BIND_TEXTURES ) );

		for (usize i = 0; i < sTech.sInit.aBranchPasses.Count(); ++i)
			sTech.aPassCache.PushBack( TPassName( sTech.sInit.aBranchPasses[i].sName, i, IRTPass::BRANCH ) );

		for (usize i = 0; i < sTech.sInit.aCustomPasses.Count(); ++i)
			sTech.aPassCache.PushBack( TPassName( sTech.sInit.aCustomPasses[i].sName, i, IRTPass::CUSTOM ) );

		for (usize i = 0; i < sTech.sInit.aCyclesPasses.Count(); ++i)
			sTech.aPassCache.PushBack( TPassName( sTech.sInit.aCyclesPasses[i].sName, i, IRTPass::CYCLE ) );

		for (usize i = 0; i < sTech.sInit.aGLStatesPasses.Count(); ++i)
			sTech.aPassCache.PushBack( TPassName( sTech.sInit.aGLStatesPasses[i].sName, i, IRTPass::SET_GL_STATE ) );

		for (usize i = 0; i < sTech.sInit.aPostProcessPasses.Count(); ++i)
			sTech.aPassCache.PushBack( TPassName( sTech.sInit.aPostProcessPasses[i].sName, i, IRTPass::POSTPROCESS ) );

		for (usize i = 0; i < sTech.sInit.aSetRTPasses.Count(); ++i)
			sTech.aPassCache.PushBack( TPassName( sTech.sInit.aSetRTPasses[i].sName, i, IRTPass::SET_RENDER_TARGET ) );

		for (usize i = 0; i < sTech.sInit.aSwizzlePasses.Count(); ++i)
			sTech.aPassCache.PushBack( TPassName( sTech.sInit.aSwizzlePasses[i].sName, i, IRTPass::SWIZZLE ) );

		bool		res		= true;
		IRTPass *	p_pass	= nullptr;

		for (usize i = 0; i < sTech.sInit.aPasses.Count(); ++i)
		{
			res = _CreatePass( sTech.sInit.aPasses[i], p_pass, aPasses.Back(), sTech );

			if ( res )
				aPasses.PushBack( p_pass );
			else
				break;
		}
		return res;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_CreatePass(const string &sName, IRTPass *&pPass, IRTPass *pParent, const TTechParams &sTech)
	{
		static const string		s_builtin( "builtin_" );

		if ( s_builtin.CmpPrefix( sName, s_builtin.Length() ) )
		{
			string			s_name;
			string_array_t	a_params;

			if ( !GetBuiltinFunc( sName, s_name, a_params ) )
				return false;

			for (usize i = 0; i < _aBuiltinPasses.Count(); ++i) {
				if ( s_name == _aBuiltinPasses[i].sName )
				{
					IRTPass	*p_pass = nullptr;

					if ( _aBuiltinPasses[i].pProc( pPass, a_params, pParent, sTech ) )
						return true;

					break;
				}
			}
			LOG( (string("unknown built-in pass: \"") << sName << '.').cstr(), e_log_msg::ERROR_3 );
			return false;
		}

		for (usize i = 0; i < sTech.aPassCache.Count(); ++i)
		{
			if ( sName == *sTech.aPassCache[i].pName )
			{
				bool	b_res	= false;
				usize	idx		= sTech.aPassCache[i].uIndex;

				switch ( sTech.aPassCache[i].eType )
				{
					case IRTPass::BIND_TEXTURES :
						b_res = _CreateBindTexturesPass( pPass, pParent, sTech.sInit.aBindTexPasses[idx], sTech );
						break;

					case IRTPass::BRANCH :
						b_res = _CreateBranchPass( pPass, pParent, sTech.sInit.aBranchPasses[idx], sTech );
						break;

					case IRTPass::CUSTOM :
						b_res = _CreateCustomPass( pPass, pParent, sTech.sInit.aCustomPasses[idx], sTech );
						break;

					case IRTPass::CYCLE :
						b_res = _CreateCyclePass( pPass, pParent, sTech.sInit.aCyclesPasses[idx], sTech );
						break;

					case IRTPass::POSTPROCESS :
						b_res = _CreatePostProcessPass( pPass, pParent, sTech.sInit.aPostProcessPasses[idx], sTech );
						break;

					case IRTPass::SET_GL_STATE :
						b_res = _CreateSetStatesPass( pPass, pParent, sTech.sInit.aGLStatesPasses[idx], sTech );
						break;

					case IRTPass::SET_RENDER_TARGET :
						b_res = _CreateSetRenderTargetsPass( pPass, pParent, sTech.sInit.aSetRTPasses[idx], sTech );
						break;

					case IRTPass::SWIZZLE :
						b_res = _CreateSwizzlePass( pPass, pParent, sTech.sInit.aSwizzlePasses[idx], sTech );
						break;
				};

				ASSERT( b_res && "can't create pass" );
				return b_res;
			}
		}
		WARNING( "unknown pass" );
		return false;
	}

/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_CreateRenderTarget(const TRenderTarget &sRT, TTechParams &sTech)
	{
		const ivec2	&	screen		= WINDOW()->GetRenderParams().sWinSize;
		float			f_min_size	= 1.f / (float)Min( screen.x, screen.y );
		TPPTexInfo		s_info;

		s_info.vSize	= uvec3( sRT.uWidth, sRT.uHeight, sRT.uDepth );
		s_info.eFlags	= sRT.eFlags;
		s_info.eSwizzle	= sRT.eSwizzle;
		s_info.eRTFormat= sRT.eTexFormat;
		s_info.uSamples	= sRT.uSamples;

		if ( sRT.fSize > f_min_size )
		{
			s_info.vSize.x	= Round( screen.x * sRT.fSize );
			s_info.vSize.y	= Round( screen.y * sRT.fSize );
			s_info.fSize	= sRT.fSize;
		}
		
		switch ( sRT.uTexType )
		{
			case TPPTypes::TEX_2D		:	s_info.eTexType = e_resource::TEXTURE_2D;			break;
			case TPPTypes::TEX_2D_A		:	s_info.eTexType = e_resource::TEXTURE_2D_ARRAY;		break;
			case TPPTypes::TEX_3D		:	s_info.eTexType = e_resource::TEXTURE_3D;			break;
			case TPPTypes::CUBE_MAP		:	s_info.eTexType = e_resource::TEXTURE_CUBE_MAP;		break;
			case TPPTypes::TEX_2D_MS	:	s_info.eTexType = e_resource::TEXTURE_2D_MS;		break;
			case TPPTypes::TEX_2D_MSA	:	s_info.eTexType = e_resource::TEXTURE_2D_MS_ARRAY;	break;
			default						:	return false;
		}

		CTexturePtr			p_tex;
		e_rt_flags::type	e_flags = e_rt_flags::RENDER_TECHNIQUE;

		CHECK_RETURN( RENDER()->GetPPManager()->GetRenderTarget( s_info, p_tex, e_flags ) );
		sTech.aRenderTargets.PushBack( TRenderTargetInfo( p_tex, sRT.sName ) );
		return true;
	}

/*
=================================================
	
=================================================
*/
	bool CRTPassManager::CreatePasses(const TConfiguredRTInit &sInit, rt_pass_array_t &aPasses)
	{
		CHECK_ARGUMENT( !aPasses.Empty() );

		TTechParams		s_tech( sInit );

		CHECK_RETURN( _ProcessConsole( sInit.aConsole, s_tech ) );

		// create render targets
		RENDER()->GetPPManager()->EnableBarrier(0);
		
		for (usize i = 0; i < sInit.aRenderTargets.Count(); ++i)
			CHECK_RETURN( _CreateRenderTarget( sInit.aRenderTargets[i], s_tech ) );
		
		RENDER()->GetPPManager()->DisableBarrier();

		// create passes
		CHECK_RETURN( _CreatePasses( aPasses, s_tech ) );

		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::RegisterBuiltinPass(const string &sName, PCreateBuiltinPassProc_t pProc)
	{
		CHECK_ARGUMENT( !sName.Empty() && pProc != nullptr );
		ASSERT( !UnregisterBuiltinPass( sName ) && "override built-in pass type" );

		_aBuiltinPasses.PushBack( _TBuiltin( pProc, sName ) );
		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::UnregisterBuiltinPass(const string &sName)
	{
		for (usize i = 0; i < _aBuiltinPasses.Count(); ++i) {
			if ( _aBuiltinPasses[i].sName == sName )
			{
				_aBuiltinPasses.FastErase( i );
				return true;
			}
		}
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_s_CreateDrawLightsPass(IRTPass *&pPass, const string_array_t &aParams, IRTPass *pParent, const TTechParams &sTech)
	{
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_s_CreateSetupShadowPass(IRTPass *&pPass, const string_array_t &aParams, IRTPass *pParent, const TTechParams &sTech)
	{
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_s_CreateSetupLightPass(IRTPass *&pPass, const string_array_t &aParams, IRTPass *pParent, const TTechParams &sTech)
	{
		return false;
	}

/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_s_CreateUseUserPostProcessPass(IRTPass *&pPass, const string_array_t &aParams, IRTPass *pParent, const TTechParams &sTech)
	{
		CBuiltinUseUserPostProcess	*p_pass = new CBuiltinUseUserPostProcess( pParent );
		const uint					u_index = aParams.Empty() ? 0 : String::ToInt32( aParams[0] );

		if ( p_pass->Create( u_index ) ) {
			pPass = p_pass;
			return true;
		}
		p_pass->Free();
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_s_CreateDrawFullscreenQuadPass(IRTPass *&pPass, const string_array_t &aParams, IRTPass *pParent, const TTechParams &sTech)
	{
		CBaseProgramShellPtr	p_prog;
		bool					b_res = false;
		bool					b_flip = true;

		if ( aParams.Empty() )
			b_res = RENDER()->GetDefaultProgram( e_def_program::SIMPLE_2D, p_prog );
		else
		if ( IsValue( aParams[0][0] ) )
		{
			b_res = RENDER()->GetDefaultProgram( (e_def_program::type)String::ToInt32( aParams[0] ), p_prog );
		}
		else
		if ( IsIdent( aParams[0][0] ) )
		{
			e_def_program::type	e_prog = e_def_program::UNKNOWN;

			if ( aParams[0] == "font" )					e_prog = e_def_program::FONT;				else
			if ( aParams[0] == "simple2d" )				e_prog = e_def_program::SIMPLE_2D;			else
			if ( aParams[0] == "simple2d_color" )		e_prog = e_def_program::SIMPLE_2D_COLOR;	else
			if ( aParams[0] == "simple3d" )				e_prog = e_def_program::SIMPLE_3D;			else
			if ( aParams[0] == "simple3d_cm" )			e_prog = e_def_program::SIMPLE_3D_CM;		else
			if ( aParams[0] == "font_gs" )				e_prog = e_def_program::FONT_GS;			else
			if ( aParams[0] == "simple2d_gs" )			e_prog = e_def_program::SIMPLE_2D_GS;		else
			if ( aParams[0] == "simple2d_color_gs" )	e_prog = e_def_program::SIMPLE_2D_COLOR_GS;

			if ( e_prog != e_def_program::UNKNOWN )
				b_res = RENDER()->GetDefaultProgram( e_prog, p_prog );
		}
		else
		if ( IsString( aParams[0][0] ) )
		{
			b_res = RESMAN()->Load( e_resource::PROGRAM_SHELL, p_prog, aParams[0].cstr()+1 );
		}

		if ( !b_res )
			return false;
		

		if ( aParams.Count() >= 2 )
		{
			if ( IsIdent( aParams[1][0] ) )
			{
				bool	b_true  = aParams[1] == "true";
				bool	b_false = aParams[1] == "false";

				ASSERT( b_true != b_false );

				b_flip = b_true ? true : (b_false ? false : true);
			}
			else
			if ( IsValue( aParams[1][0] ) )
			{
				b_flip = !!String::ToInt32( aParams[1] );
			}
			else {
				WARNING( "unknown argument" );
			}
		}

		CBuiltinDrawFullscreenQuad	*p_pass = new CBuiltinDrawFullscreenQuad( pParent );

		if ( p_pass->Create( p_prog, b_flip ) ) {
			pPass = p_pass;
			return true;
		}
		p_pass->Free();
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_s_CreateDrawRenderQueuePass(IRTPass *&pPass, const string_array_t &aParams, IRTPass *pParent, const TTechParams &sTech)
	{
		uint		u_layer = 0;
		bool		b_res	= false;


		if ( aParams.Empty() )
			b_res = false;
		else
		if ( IsValue( aParams[0][0] ) ) {
			u_layer = String::ToInt32( aParams[0] );
			b_res = true;
		}
		else
		if ( IsIdent( aParams[0][0] ) )
		{
			if ( aParams[0] == "iteration" ) {
				u_layer = -1;
				b_res = true;
			}
		}

		if ( !b_res )
			return false;


		if ( sTech.bForwardRender )
		{
			/*CFRBuiltinDrawRenderQueue	*p_pass = new CFRBuiltinDrawRenderQueue( pParent );

			if ( p_pass->Create( u_layer ) ) {
				pPass = p_pass;
				return true;
			}
			p_pass->Free();*/
		}
		else
		{
			CDRBuiltinDrawRenderQueue	*p_pass = new CDRBuiltinDrawRenderQueue( pParent );

			if ( p_pass->Create( u_layer ) ) {
				pPass = p_pass;
				return true;
			}
			p_pass->Free();
		}
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_s_CreateDrawRenderQueueOCPass(IRTPass *&pPass, const string_array_t &aParams, IRTPass *pParent, const TTechParams &sTech)
	{
		uint				u_layer = 0;
		bool				b_res	= false;
		CShaderProgramPtr	p_shader;


		if ( aParams.Count() < 2 )
			return false;

		if ( IsString( aParams[0][0] ) )
		{
			CHECK_RETURN( RESMAN()->Load( e_resource::SHADER_PROGRAM, p_shader,
										  aParams[0].cstr()+1, e_prog_flags::LINK ) );
		}
		else
			return false;

		if ( IsValue( aParams[1][0] ) ) {
			u_layer = String::ToInt32( aParams[1] );
			b_res = true;
		}
		else
		if ( IsIdent( aParams[1][0] ) )
		{
			if ( aParams[1] == "iteration" ) {
				u_layer = -1;
				b_res = true;
			}
		}

		if ( !b_res )
			return false;

		
		if ( sTech.bForwardRender )
		{
			/*CFRBuiltinDrawRenderQueueOC	*p_pass = new CFRBuiltinDrawRenderQueueOC( pParent );

			if ( p_pass->Create( p_shader, u_layer ) ) {
				pPass = p_pass;
				return true;
			}
			p_pass->Free();*/
		}
		else
		{
			CBuiltinDrawRenderQueueOC	*p_pass = new CBuiltinDrawRenderQueueOC( pParent );

			if ( p_pass->Create( p_shader, u_layer ) ) {
				pPass = p_pass;
				return true;
			}
			p_pass->Free();
		}
		return false;
	}

/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_s_CreateProfilerBeginPass(IRTPass *&pPass, const string_array_t &aParams, IRTPass *pParent, const TTechParams &sTech)
	{
		const char	*	p_name = nullptr;

		if ( aParams.Empty() ) {}
		else
		if ( IsIdent( aParams[0][0] ) )
			p_name = aParams[0].cstr();
		else
		if ( IsString( aParams[0][0] ) )
			p_name = aParams[0].cstr();

		if ( p_name == nullptr )
			return false;

		CBuiltinProfilerBegin	*p_pass = new CBuiltinProfilerBegin( pParent );

		if ( p_pass->Create( p_name ) ) {
			pPass = p_pass;
			return true;
		}
		p_pass->Free();
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_s_CreateProfilerEndPass(IRTPass *&pPass, const string_array_t &aParams, IRTPass *pParent, const TTechParams &sTech)
	{
		const char	*	p_name = nullptr;

		if ( aParams.Empty() ) {}
		else
		if ( IsIdent( aParams[0][0] ) )
			p_name = aParams[0].cstr();
		else
		if ( IsString( aParams[0][0] ) )
			p_name = aParams[0].cstr();

		if ( p_name == nullptr )
			return false;

		CBuiltinProfilerEnd	*p_pass = new CBuiltinProfilerEnd( pParent );

		if ( p_pass->Create( p_name ) ) {
			pPass = p_pass;
			return true;
		}
		p_pass->Free();
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_s_CreateClearBufferPass(IRTPass *&pPass, const string_array_t &aParams, IRTPass *pParent, const TTechParams &sTech)
	{
		bool				b_res	= false;
		e_fbo_attach::type	e_buf	= e_fbo_attach::COLOR_0;

		if ( aParams.Empty() )
		{}
		else
		if ( IsValue( aParams[0][0] ) ) {
			e_buf = (e_fbo_attach::type) String::ToInt32( aParams[0] );
			b_res = true;
		}
		else
		if ( IsIdent( aParams[0][0] ) )
		{
			static const string		s_sColor( "color_" );

			if ( aParams[0] == "all" )					{ e_buf = e_fbo_attach::_UNKNOWN; b_res = true; }	else
			if ( aParams[0] == "depth" )				{ e_buf = e_fbo_attach::DEPTH;    b_res = true; }	else
			if ( aParams[0] == "stancil" )				{ e_buf = e_fbo_attach::STENCIL;  b_res = true; }	else
			if ( aParams[0].CmpPrefix( s_sColor, 0 ) )	{
				e_buf = e_fbo_attach::type( e_fbo_attach::COLOR_0 + String::ToInt32( aParams[0].cstr() + s_sColor.Length() ) );
				b_res = true;
			}
		}
			
		if ( !b_res )
			return false;

		
		CBuiltinClearBuffer *	p_pass	= new CBuiltinClearBuffer( pParent );

		if ( e_buf == e_fbo_attach::_UNKNOWN )
		{
			b_res = p_pass->Create( -1, e_buf );
		}
		else
		if ( aParams.Count() == 2 )
		{
			if ( IsFloat( aParams[1].cstr() ) )
				b_res = p_pass->Create( String::ToFloat( aParams[1] ), e_buf );
			else
				b_res = p_pass->Create( String::ToInt32( aParams[1] ), e_buf );
		}
		else
		if ( aParams.Count() == 5 )
		{
			const color4f	s_color( String::ToFloat( aParams[1] ),
									 String::ToFloat( aParams[2] ),
									 String::ToFloat( aParams[3] ),
									 String::ToFloat( aParams[4] ) );
			b_res = p_pass->Create( s_color, e_buf );
		}

		if ( b_res ) {
			pPass = p_pass;
			return true;
		}
		p_pass->Free();
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_s_CreateSetCameraPass(IRTPass *&pPass, const string_array_t &aParams, IRTPass *pParent, const TTechParams &sTech)
	{
		e_camera::type	e_cam_type	= e_camera::VIEW;
		uint			u_index		= 0;
		bool			b_res		= false;

		if ( aParams.Empty() )
		{}
		else
		if ( IsValue( aParams[0][0] ) ) {
			e_cam_type	= (e_camera::type) String::ToInt32( aParams[0] );
			b_res		= true;
		}
		else
		if ( IsIdent( aParams[0][0] ) )
		{
			if ( aParams[0] == "view" )			{ e_cam_type = e_camera::VIEW;		 b_res = true; }	else
			if ( aParams[0] == "mini_view" )	{ e_cam_type = e_camera::MINI_VIEW;  b_res = true; }	else
			if ( aParams[0] == "shadow" ||
				 aParams[0] == "light" )		{ e_cam_type = e_camera::LIGHT;		 b_res = true; }	else
			if ( aParams[0] == "reflection" )	{ e_cam_type = e_camera::REFLECTION; b_res = true; }
		}

		if ( aParams.Count() >= 2 )
			u_index = String::ToInt32( aParams[1] );
	
		if ( !b_res )
			return false;

		CBuiltinSetCamera	*p_pass = new CBuiltinSetCamera( pParent );

		if ( p_pass->Create( e_cam_type, u_index ) ) {
			pPass = p_pass;
			return true;
		}
		p_pass->Free();
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_CreateCyclePass(IRTPass *&pPass, IRTPass *pParent, const TRTCyclePass &sInfo, const TTechParams &sTech)
	{
		CRTCyclePass *	p_pass		 = new CRTCyclePass( pParent );
		IRTPass		 *	p_cycle_pass = nullptr;

		if ( _CreatePass( sInfo.sPass, p_cycle_pass, p_pass, sTech ) &&
			 p_pass->Create( sInfo.vIterations, p_cycle_pass ) )
		{
			pPass = p_pass;
			return true;
		}

		if ( p_cycle_pass != nullptr )
			p_cycle_pass->Free();

		p_pass->Free();
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_CreateCustomPass(IRTPass *&pPass, IRTPass *pParent, const TRTCustomPass &sInfo, const TTechParams &sTech)
	{
		CRTCustomPass	*	p_pass		= new CRTCustomPass( pParent );
		rt_pass_array_t		a_passes;
		IRTPass			*	p_tmp_pass	= p_pass;
		bool				b_res		= true;


		for (usize j = 0; j < sInfo.aPasses.Count(); ++j)
		{
			IRTPass	*	p_tmp = p_tmp_pass;
			b_res = _CreatePass( sInfo.aPasses[j], p_tmp_pass, p_tmp, sTech );
			
			if ( b_res )
				a_passes.PushBack( p_tmp_pass );
			else
				break;
		}

		if ( b_res && p_pass->Create( a_passes ) )
		{
			pPass = p_pass;
			return true;
		}

		for (usize i = 0; i < a_passes.Count(); ++i)
			a_passes[i]->Free();

		p_pass->Free();
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_CreateBranchPass(IRTPass *&pPass, IRTPass *pParent, const TRTBranchPass &sInfo, const TTechParams &sTech)
	{
		CRTBranchPass	*	p_pass	 = new CRTBranchPass( pParent );
		IRTPass			*	p_then	 = nullptr,
						*	p_else	 = nullptr;
		bool				b_res	 = true;

		
		b_res &= _CreatePass( sInfo.sThenPass,  p_then, p_pass, sTech );
		b_res &= _CreatePass( sInfo.sElesePass, p_else, p_pass, sTech );
		
		if ( b_res && p_pass->Create( sInfo.sIfValue, p_then, p_else ) )
		{
			pPass = p_pass;
			return true;
		}

		if ( p_then != nullptr ) p_then->Free();
		if ( p_else != nullptr ) p_else->Free();

		p_pass->Free();
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_CreateSwizzlePass(IRTPass *&pPass, IRTPass *pParent, const TRTSwizzlePass &sInfo, const TTechParams &sTech)
	{
		CRTSwizzlePass	*				p_pass	 = new CRTSwizzlePass( pParent );
		IRTPass			*				p_default= nullptr;
		CRTSwizzlePass::case_array_t	a_case;
		bool							b_res	 = true;

		for (usize i = 0; i < sInfo.aCase.Count(); ++i)
		{
			IRTPass	*	p_tmp_pass = nullptr;
			b_res = _CreatePass( sInfo.aCase[i].sPassName, p_tmp_pass, p_pass, sTech );

			if ( b_res )
				a_case.PushBack( CRTSwizzlePass::TCase( p_tmp_pass, sInfo.aCase[i].uValue ) );
			else
				break;
		}

		if ( b_res && !sInfo.sDefaultPass.Empty() )
		{
			b_res = _CreatePass( sInfo.sDefaultPass, p_default, p_pass, sTech );
		}

		if ( b_res && p_pass->Create( sInfo.sValue, a_case, p_default ) )
		{
			pPass = p_pass;
			return true;
		}

		for (usize i = 0; i < a_case.Count(); ++i) {
			a_case[i].pPass->Free();
		}

		if ( p_default != nullptr )
			p_default->Free();

		p_pass->Free();
		return false;
	}

/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_CreateSetStatesPass(IRTPass *&pPass, IRTPass *pParent, const TRTSetGLStatesPass &sInfo, const TTechParams &sTech)
	{
		CRTSetGLStatesPass *	p_pass = new CRTSetGLStatesPass( pParent );

		if ( p_pass->Create( sInfo.aStates, sInfo.sState, sInfo.eRSLock ) )
		{
			pPass = p_pass;
			return true;
		}

		p_pass->Free();
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_CreatePostProcessPass(IRTPass *&pPass, IRTPass *pParent, const TRTPostProcessPass &sInfo, const TTechParams &sTech)
	{
		pptex_array_t								a_tex;
		CRTPostProcessPass::render_target_array_t	a_rt;
		IPostProcessBasePtr							p_postprocess;

		for (usize i = 0; i < sInfo.aInputTextures.Count(); ++i)
		{
			bool	b_found = false;

			for (usize j = 0; j < sTech.aRenderTargets.Count(); ++j)
				if ( sInfo.aInputTextures[i].sName == sTech.aRenderTargets[j].sName )
				{
					a_tex.PushBack( TPostProcessTexture( sTech.aRenderTargets[j].pTexture, (e_pp_texture::type)sInfo.aInputTextures[i].eType ) );
					b_found = true;
					break;
				}

			if ( !b_found )
				return false;
		}

		for (usize i = 0; i < sInfo.aOutputTextures.Count(); ++i)
		{
			bool	b_found = false;

			for (usize j = 0; j < sTech.aRenderTargets.Count(); ++j)
				if ( sInfo.aOutputTextures[i].sName == sTech.aRenderTargets[j].sName )
				{
					a_rt.PushBack( CRTPostProcessPass::TRenderTarget( sTech.aRenderTargets[j].pTexture,
									sInfo.aOutputTextures[i].eAttach, sInfo.aOutputTextures[i].uLayer,
									sInfo.aOutputTextures[i].uLOD ) );
					b_found = true;
					break;
				}

			if ( !b_found )
				return false;
		}

		CHECK_RETURN( RESMAN()->Load( e_resource::POST_PROCESS, p_postprocess, sInfo.sPostProcess.cstr() ) );


		CRTPostProcessPass *	p_pass = new CRTPostProcessPass( pParent );

		if ( p_pass->Create( p_postprocess, a_tex, a_rt ) )
		{
			pPass = p_pass;
			return true;
		}

		p_pass->Free();
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_CreateBindTexturesPass(IRTPass *&pPass, IRTPass *pParent, const TRTBindTexturesPass &sInfo, const TTechParams &sTech)
	{
		pptex_array_t	a_tex;

		for (usize i = 0; i < sInfo.aTextures.Count(); ++i)
		{
			bool	b_found = false;

			for (usize j = 0; j < sTech.aRenderTargets.Count(); ++j)
				if ( sInfo.aTextures[i].sName == sTech.aRenderTargets[j].sName )
				{
					a_tex.PushBack( TPostProcessTexture( sTech.aRenderTargets[j].pTexture, (e_pp_texture::type)sInfo.aTextures[i].eType ) );
					b_found = true;
					break;
				}

			if ( !b_found )
				return false;
		}

		CRTBindTexturesPass *	p_pass = new CRTBindTexturesPass( pParent );

		if ( p_pass->Create( a_tex ) )
		{
			pPass = p_pass;
			return true;
		}
		p_pass->Free();
		return false;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRTPassManager::_CreateSetRenderTargetsPass(IRTPass *&pPass, IRTPass *pParent, const TRTSetRenderTargetsPass &sInfo, const TTechParams &sTech)
	{
		CRTSetRenderTargetsPass::render_target_array_t	a_rt;

		for (usize i = 0; i < sInfo.aTargets.Count(); ++i)
		{
			bool	b_found = false;

			for (usize j = 0; j < sTech.aRenderTargets.Count(); ++j)
				if ( sInfo.aTargets[i].sName == sTech.aRenderTargets[j].sName )
				{
					a_rt.PushBack( CRTSetRenderTargetsPass::TRenderTarget( sTech.aRenderTargets[j].pTexture,
									sInfo.aTargets[i].eAttach, sInfo.aTargets[i].uLayer, sInfo.aTargets[i].uLOD ) );
					b_found = true;
					break;
				}

			if ( !b_found )
				return false;
		}


		CRTSetRenderTargetsPass *	p_pass = new CRTSetRenderTargetsPass( pParent );

		if ( p_pass->Create( a_rt ) )
		{
			pPass = p_pass;
			return true;
		}
		p_pass->Free();
		return false;
	}

//-------------------------------------------------------------------

}	// RenderUtils
}	// Engine
